package sg.edu.nus.iss.billing.model;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class BaseModel implements Serializable {

	/**
	 * @author ZiFeng, HeeLing, BeeHong
	 *
	 */
	private static final long serialVersionUID = 1L;

	/**
	 * Get the state of the DTO as a Map
	 *
	 * @return   void
	 */
	public java.util.Map<String, Object> getMap() {
		java.util.HashMap<String, Object> mapState = new java.util.HashMap<String, Object>();
		String strFieldName;
		String strMethodName;

		Field[] fields = getAllFields();
		Method method;

		for (int intCnt = 0; intCnt < fields.length; intCnt++) {
			strFieldName = fields[intCnt].getName();
			strMethodName = "get" + (char) (strFieldName.charAt(0) - 32) + strFieldName.substring(1);
			try {
				method = getMethod(strMethodName, null);
				mapState.put(strFieldName, method.invoke(this));
			} catch (Exception ex) {
				continue;
			}
		}
		return mapState;
	}
	
	/**
	 * Get all Fields
	 */
	private Field[] getAllFields() {
		Class<? extends BaseModel> me = this.getClass();
		Class<?> su = me.getSuperclass();
		int intLen;

		Field[] myFields = me.getDeclaredFields();
		Field[] suFields;
		Field[] fields;
		intLen = myFields.length;
		do {
			suFields = su.getDeclaredFields();
			intLen += suFields.length;
		} while (!(su = su.getSuperclass()).getName().equals("java.lang.Object"));

		fields = new Field[intLen];

		for (int intCnt = 0; intCnt < myFields.length; intCnt++) {
			fields[intCnt] = myFields[intCnt];
		}
		intLen = myFields.length;
		su = me.getSuperclass();
		do {
			suFields = su.getDeclaredFields();
			for (int intCnt = 0; intCnt < suFields.length; intCnt++) {
				fields[intLen + intCnt] = suFields[intCnt];
			}
			intLen += suFields.length;
		} while (!(su = su.getSuperclass()).getName().equals("java.lang.Object"));

		return fields;
	}
	

	/**
	 * Get Declared Method
	 */
	private Method getMethod(String strMethodName, Class<?>[] clsArg) {
		Class<? extends BaseModel> me = this.getClass();
		Class<?> su = me.getSuperclass();
		Method method = null;
		try {
			method = me.getDeclaredMethod(strMethodName, clsArg);
		} catch (Exception ex) {
		}
		if (method != null) {
			return method;
		}
		do {
			try {
				method = su.getDeclaredMethod(strMethodName, clsArg);
			} catch (Exception ex) {
			}
			if (method != null) {
				return method;
			}
		} while (!(su = su.getSuperclass()).getName().equals("java.lang.Object"));
		return method;
	}

}
